package com.zts.base.page.interceptor;

import com.zts.base.page.PageBound;
import com.zts.util.QueryStringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.util.Locale;

/**
 * Created by Zhangkh on 2017/6/1.
 */

@ControllerAdvice
public class PageBoundResolver implements HandlerMethodArgumentResolver, Formatter<PageBound> {
    private static Logger logger = LoggerFactory.getLogger(PageBoundResolver.class);

    private static final String PAGE = "page";

    private static final String SIZE = "size";

    private static final String OFFSET = "offset";

    private static final String LIMIT = "limit";

    private static final String TOTAL = "total";


    private static final int MAX_LIMIT = 10000;

    private static final int DEFAULT_LIMIT = 100;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return PageBound.class.isAssignableFrom(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        String text = webRequest.getNativeRequest(HttpServletRequest.class).getQueryString();
        return parse(text, null);
    }

    @Override
    public PageBound parse(String text, Locale locale) throws ParseException {
        logger.debug("pagebound resolve:{}", text);
        if (!StringUtils.hasText(text)) {
            return new PageBound(0, DEFAULT_LIMIT);
        }

        MultiValueMap<String, String> map = QueryStringUtil.parse(text);

        boolean containsTotal = false;
        int offset;
        int limit;

        String totalStr = map.getFirst(TOTAL);
        String pageStr = map.getFirst(PAGE);
        String sizeStr = map.getFirst(SIZE);
        String offsetStr = map.getFirst(OFFSET);
        String limitStr = map.getFirst(LIMIT);

        if (!StringUtils.isEmpty(totalStr)) {
            containsTotal = Boolean.valueOf(totalStr);
        }

        if (!StringUtils.isEmpty(pageStr) && !StringUtils.isEmpty(sizeStr)) {
            limit = Integer.parseInt(sizeStr);
            offset = (Integer.parseInt(pageStr) - 1) * limit;
        } else if (!StringUtils.isEmpty(offsetStr) && !StringUtils.isEmpty(limitStr)) {
            limit = Integer.parseInt(limitStr);
            offset = Integer.parseInt(offsetStr);
            containsTotal = offset % limit == 0 && containsTotal;
        } else {
            limit = DEFAULT_LIMIT;
            offset = 0;
        }

        limit = limit > MAX_LIMIT ? MAX_LIMIT : limit;

        return new PageBound(offset, limit, containsTotal);
    }

    @Override
    public String print(PageBound object, Locale locale) {
        return null;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(this);
    }

}
